EDA von Gebrauchtwagenangeboten der Website “Autoscout24”
Contents
EDA von Gebrauchtwagenangeboten der Website “Autoscout24”¶
Von Annika Scheug und Oliver Schabe, Vorlesung “Python for Data Science”, Sommersemester 2022
Einleitung¶
In diesem Projekt wird eine Explorative Datenanalyse von Gebrauchtwagenangeboten der Website “Autoscout24” durchgeführt.
Autoscout24 (https://www.autoscout24.de/) ist eine Online-Plattform zum Kauf und Verkauf von Neu- und Gebrauchtwagen.
Die Startseite von Autoscout24 sieht folgendermaßen aus:

Die Suchergebnisse werden in einer Liste dargestellt, wobei immer 20 Fahrzeuge pro Seite angezeigt werden und je Suchergebniss 20 Seiten:

Ziel des Projektes ist es, Daten über Zustand und Ausstattung verschiedener Fahrzeuge aus dem Quellcode der Website abzuziehen und diese Daten anschließend ausführlich zu analysieren.
Bei der Analyse der Daten sollen mögliche Korrelationen zwischen den in den Angeboten angegebenen Werten untersucht werden. Der Schwerpunkt soll dabei auf dem Preis und den Fahrzeugeigenschaften liegen, die einen relevanten Einfluss auf den Verkaufspreis haben (wie möglicherweise Kilometerstand, Alter des Fahrzeuges etc.).
Als möglicher praktischer Anwendungsfall der hier gesammelten Erkentnisse könnte beispielsweise ein Tool sein, welches interessierten Käufern oder Verkäufern realistische Preisvorschläge auf Basis von Angaben zum Fahrzeugszustand macht.
Die Entwicklung einer solchen Applikation ist jedoch nicht im Scope dieses Projektes.
Import¶
Zunächst werden alle für dieses Projekt benötigten Packages und Bibliotheken importiert.
#Basics
import pandas as pd
import numpy as np
#Webcrawling
#pip install beautifulsoup4
from bs4 import BeautifulSoup
import requests
#Deactivate warnings
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
#Data visualization
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objs as go
import plotly.io as pio
import plotly.figure_factory as ff
import plotly.offline as pyo
# Set notebook mode to work in offline
pyo.init_notebook_mode()
import seaborn as sns
np.set_printoptions(precision=6)
np.set_printoptions(suppress=True)
pd.set_option("display.max_columns", 200)
pd.set_option("display.max_rows", 200)
#Geo visualization
import folium
#!pip install geopy
from geopy.geocoders import Nominatim
#Postgre SQL
import psycopg2
import json
from sqlalchemy import create_engine
#Regression
import statsmodels.formula.api as smf
Webcrawling & Creation of Dataframe¶
Als Erstes ist es notwendig, die Fahrzeugdaten von der Webseite Autoscout24 zu crawlen und in einem Dataframe zu speichern.
Für das Crawlen der Daten wird die Methode extractPageCarDF definiert. Dieser muss beim Aufruf die Variable URL mitgegeben werden. Dabei handelt es sich um den Link zu einem Autoscout24 Suchergebnis, welches stehts 20 Autos beinhaltet (sofern sie den Suchkriterien entsprechen).
Jedes Auto wird dabei vom HTML Element Article umschlossen. Daher wird eine Schleife implementiert, welche für jedes Auto im Suchergebnis die nachfolgenden Daten aus den dazugehörigen HTML Elementen der Webseite extrahiert:
Titel
Fahrzeugversion
Untertitel
Preis
Leasingpreis
Fahrzeugstandort
Falls eines der HTML-Elemente nicht gefunden werden kann, wird jede der Anweisungen durch einen try except Block umschlossen. Falls kein Eintrag gefunden wird, wird der jeweilige Wert mit einem NULL-Wert belegt.
Eine Besonderheit ist zudem der Preis. Wird das Element ListItem_pricerow gefunden, handelt es sich um einen Verkaufspreis und kein Leasingangebot. Leasing wird daher False gesetzt. Wird dieses Element nicht gefunden, sondern LeasingPrice_price handelt es sich um ein Leasing Angebot.
Diese Daten werden dem Dataframe pageCarDF hinzugefügt.
In einer weiteren Schleife werden die folgenden Fahrzeugdetaildaten aus dem HTML Div Container VehicleDetailTable abgezogen:
Es wird zunächst ein leeres Dataframe initialisiert.
In einer Schleife wird für jedes Fahrzeug die leere Liste VehicleDetailList erzeugt und dieser in einer inneren Schleife jedes Element der VehicleDetailTable hinzugefügt.
Die Liste wird anschließend dem VehicleDetailDF hinzugefügt. Hierfür ist ein try except notwendig. Leasing Fahrzeuge haben ein zweites Element namens VehicleDetailTable, welches allerdings nur 3 Einträge zum Themengebiet Leasing hat. Der Versuch diese Listen mit 3 Einträgen dem VehicleDetailDF hinzuzufügen, läuft aufgrund nicht passender Längen auf Fehler. Dieser Fehler wird im except Block bewusst mit einem Continue abgefangen. Die Leasing VehicleDetailLists werden nicht weiter benötigt und fallen somit raus.
Nun liegt das pageCarDF und das VehicleDetailDF vor, welche beide je Fahrzeug eine Zeile beinhalten.
Die beiden Dataframes werden mithilfe der merge-Methode über den Index gejoined.
Die Methode gibt das Dataframe pageCarDF als return value zurück. Diese beinhaltet alle relevanten Daten von den Fahrzeugen einer Suchergebnisseite (in der Regel 20 Fahrzeuge).
def extractPageCarDF(URL):
soup=BeautifulSoup(requests.get(URL).text,"html.parser")
pageCarDF=pd.DataFrame()
for car in soup.findAll("article"):
data = car.find("div", {"class": lambda L: L and L.startswith("ListItem_wrapper")})
try:
header = data.find("h2").text
except:
header = np.NaN
try:
version = data.find("span", {"class": lambda L: L and L.startswith("ListItem_version")}).text
except:
version = np.NaN
try:
subtitle = data.find("span", {"class": lambda L: L and L.startswith("ListItem_subtitle")}).text
except:
subtitle = np.NaN
try:
#Versuch Preis Element zu finden
price = data.find("div", {"class": lambda L: L and L.startswith("ListItem_pricerow")}).text
leasing = False
except:
#wenn oberes Element nicht gefunden werden kann, handelt es sich um einen Leasing Wagen, mit dem nachfolgenden HTML Element
price = data.find("span", {"class": lambda L: L and L.startswith("LeasingPrice_price")}).text
leasing = True
try:
location = car.find("span", {"style": lambda L: L and L.startswith("grid-area:address")}).text
except:
location = np.NaN
#Daten dem pageCarDF hinzufügen
pageCarDF = pageCarDF.append({"Titel":header, "Version":version, "Untertitel":subtitle, "Preis":price, "Leasing":leasing, "Standort":location}, ignore_index=True)
#VehicleDetailTable
VehicleDetailDF = pd.DataFrame()
for car in soup.findAll("div" , {"class":"VehicleDetailTable_container__mUUbY"}):
VehicleDetailList = []
for c in car:
VehicleDetailList.append(c.text)
try:
VehicleDetailDF = VehicleDetailDF.append({"km":VehicleDetailList[0], "Erstzulassung":VehicleDetailList[1], "PS":VehicleDetailList[2], "Zustand":VehicleDetailList[3], "Fahrzeughalter":VehicleDetailList[4], "Getriebe":VehicleDetailList[5], "Kraftstoff": VehicleDetailList[6], "Verbrauch_l_pro_100km":VehicleDetailList[7], "Emissionen_g_pro_km":VehicleDetailList[8]}, ignore_index=True)
except:
continue #VehicleDetailLists mit Länge 3 sind extra VehicleDetailTables, die nur bei Leasing Wagen vorkommen. Diese sollen nicht übernommen werden, daher Continue
#Join pageCarDF und VehicleDetailDF
pageCarDF = pd.merge(pageCarDF, VehicleDetailDF, left_index=True, right_index=True)
return pageCarDF
Die Methode extractPageCarDF gilt es nun mit den passenden Paramentern aufzurufen.
Es werden zunächst zwei leere Dataframes initialisiert.
Die Suche auf Autoscout24 wurde zunächst komplett ohne Filter aufgerufen. Pro Suchergebnis gibt die Webseite ingesamt 20 Suchergebnisseiten mit jeweils 20 Fahrzeugen aus. Somit können mit einer Suche maximal 20 * 20 = 400 Autos von der Webseite gecrawlt werden.
Da für die Analysen im Projekt mehr als 400 Datensätze gewünscht sind, wird ein Filter “Erstzulassung von” (fregfrom) und “Erstzulassung bis” (fregto) gesetzt. Die Jahreszahlen werden in der Liste fregtoList von 1990 bis 2022 in 1 Jahresschritten gewählt.
In einer Schleife wird zunächst der Filter auf die jeweilige Jahreszahl gesetzt. In einer inneren Schleife wird jeweils die Ergebnisseite der Suche festgelegt. Somit werden pro Iteration der äußeren Schleife 20 Seiten des Suchergebnisses gecrawlt.
Dafür wird zunächst die URL aus “Erstzulassung von” fregfrom= , “Erstzulassung bis” fregto= und Suchergebnisseite page erstellt. Die URL wird an die Methode extractPageCarDF übergeben und diese ausgeführt.
Das resultierende Dataframe pageCarDF mit 20 Fahrzeugen wird dem Dataframe AutoDFraw angehängt. Anschließend wird die Methode für die nächste Seite im Suchergebnis ausgeführt und das Ergebnis wieder AutoDFraw hinzufügt.
Dataframe pageCarDF wird somit bei jeder Ausführung der Methode extractPageCarDF neu erstellt, während Dataframe AutoDFraw immer weiter wächst.
Die Methode wird für jeden Filter “Erstzulassung bis” für 20 Suchergebnisseiten ausgeführt, sodass das Dataframe AutoDFraw am Ende über 6000 Einträge enhält.
AutoDFraw=pd.DataFrame()
pageCarDF=pd.DataFrame()
baselink = "https://www.autoscout24.de/lst?fregfrom="
fregList = list(range(1990, 2022, 1))
for freg in fregList:
for page in range(20):
URL = baselink + str(freg) + "&fregto=" + str(freg) + "&page=" + str(page)
pageCarDF = extractPageCarDF(URL)
AutoDFraw=pd.concat([AutoDFraw, pageCarDF],axis=0, ignore_index=True)
AutoDFraw
| Titel | Version | Untertitel | Preis | Leasing | Standort | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | NaN | € 2.950,-Keine Angabe | False | DE-92318 Neumarkt | 139.800 km | 06/1990 | 66 kW (90 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | NaN | € 23.900,- | False | Contáctanos en: • ES-27003 LUGO | 73.000 km | 01/1990 | 147 kW (200 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | NaN | € 31.500,- | False | Contáctanos en: • ES-15800 MELIDE | 90.000 km | 03/1990 | 143 kW (194 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | NaN | € 73.900,-Keine Angabe | False | Ihr Verkaufsteam • DE-49076 Osnabrück | 75.156 km | 06/1990 | 150 kW (204 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | NaN | € 19.900,- | False | Contáctanos en: • ES-46006 VALENCIA | 79.000 km | 09/1990 | 94 kW (128 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12174 | Audi A3 | advanced 40TFSI S-line PDC SMARTINT | Käsmann - die große Auswahl im Neckar-Odenwald... | € 37.930,-Keine Angabe | False | Audi: 06261-9282-555 VW+Skoda: 06261-9730-555 ... | 2.653 km | 12/2021 | 140 kW (190 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | - (l/100 km) | - (g/km) |
| 12175 | Volkswagen Golf | VIII 1.5 TSI OPF -Active- 6-Gang Navi/ SHZ | Standheizung, Navigationssystem, 3-Zonen-Klima... | € 25.480,-Sehr guter Preis | False | Kundenkontaktcenter • DE-24944 Flensburg | 8.400 km | 08/2021 | 96 kW (131 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | 5,1 l/100 km (komb.) | 117 g/km (komb.) |
| 12176 | Kia Ceed / cee'd | Ceed Sportswagon Spirit Rückfahrkamera | Ihr Kia und Mitsubishi Vertragshändler | € 24.489,-Fairer Preis | False | DE-39576 Stendal | 19.700 km | 05/2021 | 103 kW (140 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | 146 g/km (komb.) | |
| 12177 | BMW 318 | iA Lim. AHK|Glasdach|Navi|HUD|LED|17"LM|SHZ | Schiebedach, Einparkhilfe Kamera, Anhängerkupp... | € 33.699,-Sehr guter Preis | False | - - • DE-46149 Oberhausen | 12.103 km | 01/2021 | 115 kW (156 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | 6,3 l/100 km | 142 g/km (komb.) |
| 12178 | Dacia Spring | Business | NaN | € 22.985,-Keine Angabe | False | Ihr Team der BOB Automobile • DE-45141 Essen | 3.551 km | 07/2021 | 33 kW (45 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Elektro | - (l/100 km) | 0 g/km (komb.) |
12179 rows × 15 columns
Abschließend werden die gecrawlten Daten in einer postgreSQL Datenbank gesichert, sodass nicht bei jeder Programmausführung die Daten neu gecrawlt werden müssen.
Dafür muss zunächst eine Verbindung mit der Datenbank hergestellt werden. Das eingelesene JSON-File enthält die Datenbank-Parameter und muss von jedem Anwender mit seinen Zugangsdaten befüllt und im gleichen Dateipfad wie dieses Juypter-Notebook abgespeichert werden.
Das JSON-File benötigt folgende Informationen im gezeigten Format:

#import json file for database connection parameters
with open('configLocalDS.json') as f:
conf = json.load(f)
Anschließend wird unter Verwendung von sqlalchemy eine Verbindung zur Datenbank hergestellt.
conn_str ='postgresql://%s:%s@localhost:5432/%s'%(conf["user"], conf["passw"],conf["database"])
engine = create_engine(conn_str)
Das Dataframe wird nun in der Tabelle autoscout24cars in postgre SQL gespeichert, sofern die Tabelle noch nicht vorhanden ist.
if not engine.has_table("autoscout24cars"):
AutoDFraw.to_sql(name='autoscout24cars',index=True, index_label='index',con=engine)
else:
print("table already exists")
C:\Users\Admin\AppData\Local\Temp/ipykernel_6452/3504836538.py:1: SADeprecationWarning:
The Engine.has_table() method is deprecated and will be removed in a future release. Please refer to Inspector.has_table(). (deprecated since: 1.4)
table already exists
Als Alternative zu SQL können die Daten in Excel gespeichert und wieder eingelesen werden um einen gleichbleibenden Datenstand zur Analyse zu gewährleisten:
Diese Codezeile ist hier auskommentiert, um das Backup nur bewusst überschreiben zu können.
#AutoDFraw.to_excel("AutoDF_raw.xlsx")
Die Fahrzeugdaten von Autoscout24 wurden erfolgreich abgezogen und in einem Dataframe gespeichert. Allerdings entsprechen viele Spalten noch nicht dem gewünschten Format, da beispielsweise Sonderzeichen enthalten sind oder numerische Werte nicht als solche erkannt werden.
Aus diesem Grund muss das Dataframe nun so bearbeitet werden, dass alle Spalten in einer für die Explorative Datenanalyse sinnvollen Struktur vorliegen.
Zunächst werden die in SQL gesicherten Daten in ein neues Dataframe AutoDF geladen.
AutoDF = pd.read_sql_query('SELECT * FROM autoscout24cars',engine, index_col="index")
AutoDF
| Titel | Version | Untertitel | Preis | Leasing | Standort | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| index | |||||||||||||||
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | None | € 2.950,-Keine Angabe | False | DE-92318 Neumarkt | 139.800 km | 06/1990 | 66 kW (90 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | None | € 23.900,- | False | Contáctanos en: • ES-27003 LUGO | 73.000 km | 01/1990 | 147 kW (200 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | None | € 31.500,- | False | Contáctanos en: • ES-15800 MELIDE | 90.000 km | 03/1990 | 143 kW (194 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | None | € 73.900,-Keine Angabe | False | Ihr Verkaufsteam • DE-49076 Osnabrück | 75.156 km | 06/1990 | 150 kW (204 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | None | € 19.900,- | False | Contáctanos en: • ES-46006 VALENCIA | 79.000 km | 09/1990 | 94 kW (128 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12174 | Audi A3 | advanced 40TFSI S-line PDC SMARTINT | Käsmann - die große Auswahl im Neckar-Odenwald... | € 37.930,-Keine Angabe | False | Audi: 06261-9282-555 VW+Skoda: 06261-9730-555 ... | 2.653 km | 12/2021 | 140 kW (190 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | - (l/100 km) | - (g/km) |
| 12175 | Volkswagen Golf | VIII 1.5 TSI OPF -Active- 6-Gang Navi/ SHZ | Standheizung, Navigationssystem, 3-Zonen-Klima... | € 25.480,-Sehr guter Preis | False | Kundenkontaktcenter • DE-24944 Flensburg | 8.400 km | 08/2021 | 96 kW (131 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | 5,1 l/100 km (komb.) | 117 g/km (komb.) |
| 12176 | Kia Ceed / cee'd | Ceed Sportswagon Spirit Rückfahrkamera | Ihr Kia und Mitsubishi Vertragshändler | € 24.489,-Fairer Preis | False | DE-39576 Stendal | 19.700 km | 05/2021 | 103 kW (140 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | None | 146 g/km (komb.) |
| 12177 | BMW 318 | iA Lim. AHK|Glasdach|Navi|HUD|LED|17"LM|SHZ | Schiebedach, Einparkhilfe Kamera, Anhängerkupp... | € 33.699,-Sehr guter Preis | False | - - • DE-46149 Oberhausen | 12.103 km | 01/2021 | 115 kW (156 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | 6,3 l/100 km | 142 g/km (komb.) |
| 12178 | Dacia Spring | Business | None | € 22.985,-Keine Angabe | False | Ihr Team der BOB Automobile • DE-45141 Essen | 3.551 km | 07/2021 | 33 kW (45 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Elektro | - (l/100 km) | 0 g/km (komb.) |
12179 rows × 15 columns
Alternativ, falls die Verbindung zu postgreSQL scheitert, können die Daten auch aus dem Backup Excel geladen werden. Dieser Code ist aktuell auskommentiert und muss bei Bedarf aktiviert werden.
AutoDF=pd.read_excel("AutoDF_raw.xlsx",index_col=0)
Feature Engineering¶
Erzeugung zusätzlicher Variablen¶
Automarke¶
Eine für die Datenanalyse interessante Information ist die Automarke. Diese ist im Titel der Anzeige als erstes Wort enthalten. Daher wird zur Bestimmung der Automarke das erste Wort der Spalte Titel extrahiert und in einer neuen Spalte Marke gespeichert. Falls eine Automarke aus mehr als einem Wort besteht, wird lediglich das erste Wort übernommen.
# Erzeugen der Spalte "Marke" aus den Informationen der Spalte "Titel"
AutoDF['Marke'] = AutoDF['Titel'].str.split('\s+').str[0]
Ausstattung¶
In der Spalte Untertitel werden Ausstattungsmerkmale des Fahrzeugs aufgezählt. Einige ausgewählte Austattungsmerkmale werden als extra Spalten in das Dataframe aufgenommen. Dafür wird folgende Annahme getroffen: Ein Fahrzeug besitzt eine bestimmte Ausstattung, wenn diese in Spalte Untertitel erwähnt wird. Wird diese dort nicht erwähnt, besitzt ein Fahrzeug diese Ausstattung nicht. Dies wird mithilfe der Methode str.contains geprüft.
# Erzeugung zusätzlicher Variablen "Ausstattung"
AutoDF['Alufelgen']= AutoDF['Untertitel'].str.contains("Alufelgen")
AutoDF['Sitzheizung']= AutoDF['Untertitel'].str.contains("Sitzheizung")
AutoDF['Klimaanlage']= (AutoDF['Untertitel'].str.contains("Klimaanlage")) | (AutoDF['Untertitel'].str.contains("Klimaautomatik"))
AutoDF['Einparkhilfe']= AutoDF['Untertitel'].str.contains("Einparkhilfe ")
AutoDF['Navigationssystem']= AutoDF['Untertitel'].str.contains("Navigationssystem")
AutoDF.head()
| Titel | Version | Untertitel | Preis | Leasing | Standort | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Marke | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | NaN | € 2.950,-Keine Angabe | False | DE-92318 Neumarkt | 139.800 km | 06/1990 | 66 kW (90 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) | Volkswagen | NaN | NaN | False | NaN | NaN |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | NaN | € 23.900,- | False | Contáctanos en: • ES-27003 LUGO | 73.000 km | 01/1990 | 147 kW (200 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Renault | NaN | NaN | False | NaN | NaN |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | NaN | € 31.500,- | False | Contáctanos en: • ES-15800 MELIDE | 90.000 km | 03/1990 | 143 kW (194 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Mercedes-Benz | NaN | NaN | False | NaN | NaN |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | NaN | € 73.900,-Keine Angabe | False | Ihr Verkaufsteam • DE-49076 Osnabrück | 75.156 km | 06/1990 | 150 kW (204 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) | BMW | NaN | NaN | False | NaN | NaN |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | NaN | € 19.900,- | False | Contáctanos en: • ES-46006 VALENCIA | 79.000 km | 09/1990 | 94 kW (128 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Alfa | NaN | NaN | False | NaN | NaN |
Geodaten¶
Aus der Spalte Standort wird nun der Stadtname extrahiert, um eine spätere Kartendarstellung des Fahrzeugstandorts zu ermöglichen. Dies ist immer das letzt Wort der Spalte.
#Stadtname
AutoDF['Stadt'] = AutoDF['Standort'].str.split(' ').str[-1]
AutoDF.head()
| Titel | Version | Untertitel | Preis | Leasing | Standort | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Marke | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | Stadt | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | NaN | € 2.950,-Keine Angabe | False | DE-92318 Neumarkt | 139.800 km | 06/1990 | 66 kW (90 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) | Volkswagen | NaN | NaN | False | NaN | NaN | Neumarkt |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | NaN | € 23.900,- | False | Contáctanos en: • ES-27003 LUGO | 73.000 km | 01/1990 | 147 kW (200 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Renault | NaN | NaN | False | NaN | NaN | LUGO |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | NaN | € 31.500,- | False | Contáctanos en: • ES-15800 MELIDE | 90.000 km | 03/1990 | 143 kW (194 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Mercedes-Benz | NaN | NaN | False | NaN | NaN | MELIDE |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | NaN | € 73.900,-Keine Angabe | False | Ihr Verkaufsteam • DE-49076 Osnabrück | 75.156 km | 06/1990 | 150 kW (204 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | 0 g/km (komb.) | BMW | NaN | NaN | False | NaN | NaN | Osnabrück |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | NaN | € 19.900,- | False | Contáctanos en: • ES-46006 VALENCIA | 79.000 km | 09/1990 | 94 kW (128 PS) | Gebraucht | - (Fahrzeughalter) | Schaltgetriebe | Benzin | - (l/100 km) | - (g/km) | Alfa | NaN | NaN | False | NaN | NaN | VALENCIA |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12174 | Audi A3 | advanced 40TFSI S-line PDC SMARTINT | Käsmann - die große Auswahl im Neckar-Odenwald... | € 37.930,-Keine Angabe | False | Audi: 06261-9282-555 VW+Skoda: 06261-9730-555 ... | 2.653 km | 12/2021 | 140 kW (190 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | - (l/100 km) | - (g/km) | Audi | False | False | False | False | False | Mosbach |
| 12175 | Volkswagen Golf | VIII 1.5 TSI OPF -Active- 6-Gang Navi/ SHZ | Standheizung, Navigationssystem, 3-Zonen-Klima... | € 25.480,-Sehr guter Preis | False | Kundenkontaktcenter • DE-24944 Flensburg | 8.400 km | 08/2021 | 96 kW (131 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | 5,1 l/100 km (komb.) | 117 g/km (komb.) | Volkswagen | False | False | True | True | True | Flensburg |
| 12176 | Kia Ceed / cee'd | Ceed Sportswagon Spirit Rückfahrkamera | Ihr Kia und Mitsubishi Vertragshändler | € 24.489,-Fairer Preis | False | DE-39576 Stendal | 19.700 km | 05/2021 | 103 kW (140 PS) | Gebraucht | 1 Fahrzeughalter | Schaltgetriebe | Benzin | NaN | 146 g/km (komb.) | Kia | False | False | False | False | False | Stendal |
| 12177 | BMW 318 | iA Lim. AHK|Glasdach|Navi|HUD|LED|17"LM|SHZ | Schiebedach, Einparkhilfe Kamera, Anhängerkupp... | € 33.699,-Sehr guter Preis | False | - - • DE-46149 Oberhausen | 12.103 km | 01/2021 | 115 kW (156 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Benzin | 6,3 l/100 km | 142 g/km (komb.) | BMW | False | True | False | True | False | Oberhausen |
| 12178 | Dacia Spring | Business | NaN | € 22.985,-Keine Angabe | False | Ihr Team der BOB Automobile • DE-45141 Essen | 3.551 km | 07/2021 | 33 kW (45 PS) | Gebraucht | 1 Fahrzeughalter | Automatik | Elektro | - (l/100 km) | 0 g/km (komb.) | Dacia | NaN | NaN | False | NaN | NaN | Essen |
12179 rows × 22 columns
Entfernen unerwünschter Zeichen und Werte¶
Im nächsten Schritt wird das Dataframe um störende oder überflüssige Character bereinigt. Dazu gehören störende Satzzeichen, Währungen, Strings, etc.
Da in einzelnen Fällen zusätzlich optionale Leasingpreise noch hinter Kaufpreisen angezeigt werden, müssen zuerst alle Zeichen hinter dem ersten Kaufpreis entfernt werden. Dann werden in der nächsten Codezeile alle weiteren nicht numerischen Zeichen entfernt.
# Bereinigung der Spalte "Preis"
AutoDF['Preis'] = AutoDF['Preis'].replace('(,-).*', '',regex=True)
AutoDF['Preis'] = AutoDF['Preis'].str.replace(r'[^0-9]+', '')
Da der Monat der Erstzulassung voraussichtlich keine große Rolle spielt und die Analyse der Spalte Erstzulassung erschwert, wird dieser entfernt sowie alle übrigbleibenden nicht numerischen Zeichen.
# Bereinigung der Spalte "Erstzulassung"
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace('.*/', '',regex=True)
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace(r'[^0-9]+', '',regex=True)
Bei der PS-Angabe muss zuerst der Wert in kW entfernt werden, danach alle weiteren nicht numerischen Zeichen.
# Bereinigung der Spalte "PS"
AutoDF['PS'] = AutoDF['PS'].replace(['.*kW','\(','PS\)'], '',regex=True)
AutoDF['PS'] = AutoDF['PS'].replace(r'[^0-9]+', '',regex=True)
Die nachfolgenden Spalten enthalten im Datensatz noch Einheiten. Diese wurden bereits im Spaltentitel integriert (bspw. Emissionen_g_pro_km) und werden somit aus den Datensätzen entfernt, sodass nur noch numerische Werte verbleiben.
# Bereinigung weiterer Spalten
AutoDF['km'] = AutoDF['km'].replace(r'[^0-9]+', '',regex=True)
AutoDF['Fahrzeughalter'] = AutoDF['Fahrzeughalter'].replace(r'[^0-9]+', '',regex=True)
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(['\(l/100 km\)', 'l/100 km','\(komb.\)'], '',regex=True)
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].replace(r'[^0-9]+', '',regex=True)
Bei der Bereinigung fehlender Werte tritt das Problem auf, dass bei den Attributen Verbrauch und Emissionen fehlende Werte bei Elektroautos = 0 (also kein Verbrauch in L pro 100km) bedeuten, bei nicht Elektroautos jedoch tatsächlich fehlende Werte.
Um die Daten daher auswertbar zu machen, werden zuerst Verbrauch und Emissionen bei allen Fahrzeugen auf “NaN” gesetzt, sollten diese in irgendeiner Form fehlen. Dann werden speziell für Elektroautos die Werte auf “0” gesetzt, da nur diese Verbrauch und Emissionen von “0” haben können.
# Alle fehlenden Werte bei Verbrauch und Emissionen werden durch "NaN" ersetzt
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(['-','','0'], np.NaN,regex=True)
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].replace(['-','','0'], np.NaN,regex=True)
# da keine Angabe bei Verbrauch und Emissionen bei Elektroautos korrekt sein kann, wird der Wert wieder durch 0 ersetzt
AutoDF.loc[AutoDF.Kraftstoff == 'Elektro', 'Verbrauch_l_pro_100km'] = 0
AutoDF.loc[AutoDF.Kraftstoff == 'Elektro', 'Emissionen_g_pro_km'] = 0
Auch bei weiteren Spalten, bei denen die Angabe in der Anzeige wohl optional ist, müssen die fehlenden Werte durch “NaN” ersetzt werden um diese als fehlend bzw. “NULL” in der EDA zu erkennen.
# Weitere fehlende Werte werden durch "NaN" ersetzt
AutoDF['Fahrzeughalter'] = AutoDF['Fahrzeughalter'].replace(['-',''], np.NaN,regex=True)
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].replace('', np.NaN,regex=True)
AutoDF['km'] = AutoDF['km'].replace('', np.NaN,regex=True)
AutoDF['PS'] = AutoDF['PS'].replace('', np.NaN,regex=True)
AutoDF.head()
| Titel | Version | Untertitel | Preis | Leasing | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Marke | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | Stadt | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | NaN | 2950 | False | 139800 | 1990 | 90 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Volkswagen | NaN | NaN | False | NaN | NaN | Neumarkt |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | NaN | 23900 | False | 73000 | 1990 | 200 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Renault | NaN | NaN | False | NaN | NaN | LUGO |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | NaN | 31500 | False | 90000 | 1990 | 194 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Mercedes-Benz | NaN | NaN | False | NaN | NaN | MELIDE |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | NaN | 73900 | False | 75156 | 1990 | 204 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | BMW | NaN | NaN | False | NaN | NaN | Osnabrück |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | NaN | 19900 | False | 79000 | 1990 | 128 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Alfa | NaN | NaN | False | NaN | NaN | VALENCIA |
In der spalte Verbrauch_l_pro_100km wird das Komma zur Dezimaltrennung durch einen Punkt ersetzt, damit die Spalte als float definiert werden kann.
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].replace(',', '.',regex=True)
Abgesehen von Klimaanlage entstehen “NaN” Values in den neu erzeugten Ausstattungsspalten wenn die Spalte Untertitel “NaN” ist, daher werden diese nun durch False ersetzt (Wir gehen davon aus, dass die Ausstattung nicht enthalten ist wenn sie nicht im Untertitel erwähnt ist).
AutoDF['Alufelgen'] = AutoDF['Alufelgen'].replace(np.NaN, False)
AutoDF['Sitzheizung'] = AutoDF['Sitzheizung'].replace(np.NaN, False)
AutoDF['Einparkhilfe'] = AutoDF['Einparkhilfe'].replace(np.NaN, False)
AutoDF['Navigationssystem'] = AutoDF['Navigationssystem'].replace(np.NaN, False)
AutoDF
| Titel | Version | Untertitel | Preis | Leasing | km | Erstzulassung | PS | Zustand | Fahrzeughalter | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Marke | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | Stadt | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Volkswagen Golf | II GL Tuningfahrz. für Schrauber rostfrei viel... | NaN | 2950 | False | 139800 | 1990 | 90 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Volkswagen | False | False | False | False | False | Neumarkt |
| 1 | Renault Alpine A310 | 2.5 Turbo V6 | NaN | 23900 | False | 73000 | 1990 | 200 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Renault | False | False | False | False | False | LUGO |
| 2 | Mercedes-Benz 190 | 190E 2.5-16 | NaN | 31500 | False | 90000 | 1990 | 194 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Mercedes-Benz | False | False | False | False | False | MELIDE |
| 3 | BMW Z1 | 2,7 Ltr.+BBS+RESTAURIERT+HARDTOP | NaN | 73900 | False | 75156 | 1990 | 204 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | BMW | False | False | False | False | False | Osnabrück |
| 4 | Alfa Romeo Spider | 2.0 Quadrifoglio Verde | NaN | 19900 | False | 79000 | 1990 | 128 | Gebraucht | NaN | Schaltgetriebe | Benzin | NaN | NaN | Alfa | False | False | False | False | False | VALENCIA |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 12174 | Audi A3 | advanced 40TFSI S-line PDC SMARTINT | Käsmann - die große Auswahl im Neckar-Odenwald... | 37930 | False | 2653 | 2021 | 190 | Gebraucht | 1 | Automatik | Benzin | NaN | NaN | Audi | False | False | False | False | False | Mosbach |
| 12175 | Volkswagen Golf | VIII 1.5 TSI OPF -Active- 6-Gang Navi/ SHZ | Standheizung, Navigationssystem, 3-Zonen-Klima... | 25480 | False | 8400 | 2021 | 131 | Gebraucht | 1 | Schaltgetriebe | Benzin | 5.1 | 117 | Volkswagen | False | False | True | True | True | Flensburg |
| 12176 | Kia Ceed / cee'd | Ceed Sportswagon Spirit Rückfahrkamera | Ihr Kia und Mitsubishi Vertragshändler | 24489 | False | 19700 | 2021 | 140 | Gebraucht | 1 | Schaltgetriebe | Benzin | NaN | 146 | Kia | False | False | False | False | False | Stendal |
| 12177 | BMW 318 | iA Lim. AHK|Glasdach|Navi|HUD|LED|17"LM|SHZ | Schiebedach, Einparkhilfe Kamera, Anhängerkupp... | 33699 | False | 12103 | 2021 | 156 | Gebraucht | 1 | Automatik | Benzin | 6.3 | 142 | BMW | False | True | False | True | False | Oberhausen |
| 12178 | Dacia Spring | Business | NaN | 22985 | False | 3551 | 2021 | 45 | Gebraucht | 1 | Automatik | Elektro | 0 | 0 | Dacia | False | False | False | False | False | Essen |
12179 rows × 21 columns
In der Spalte Leasing werden die Werte noch mit 0.0 für False und 1.0 für True ausgegeben. Dies wird in Boolean Werte geändert.
AutoDF['Leasing'] = AutoDF['Leasing'].replace(0.0, False)
AutoDF['Leasing'] = AutoDF['Leasing'].replace(1.0, True)
Entfernen von fehlenden oder nicht benötigten Werten¶
Mit der .info() Methode werden nun alle Spalten des Dataframes mit deren Datentypen angezeigt.
AutoDF.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 12179 entries, 0 to 12178
Data columns (total 21 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Titel 12179 non-null object
1 Version 11900 non-null object
2 Untertitel 7238 non-null object
3 Preis 12179 non-null object
4 Leasing 12179 non-null bool
5 km 12179 non-null object
6 Erstzulassung 12179 non-null object
7 PS 12049 non-null object
8 Zustand 12179 non-null object
9 Fahrzeughalter 6218 non-null object
10 Getriebe 12179 non-null object
11 Kraftstoff 12179 non-null object
12 Verbrauch_l_pro_100km 8076 non-null object
13 Emissionen_g_pro_km 5059 non-null object
14 Marke 12179 non-null object
15 Alufelgen 12179 non-null bool
16 Sitzheizung 12179 non-null bool
17 Klimaanlage 12179 non-null bool
18 Einparkhilfe 12179 non-null bool
19 Navigationssystem 12179 non-null bool
20 Stadt 10300 non-null object
dtypes: bool(6), object(15)
memory usage: 1.6+ MB
Das Dataframe hat 22 Spalten. Davon haben die meisten den Datentyp object, obwohl es sich bei einigen davon um numerische Werte handelt. Dies muss noch geändert werden. Lediglich die Boolean Spalten wie beispielsweise Leasing wurden korrekt identifiziert.
Die meisten Spalten haben keine NULL Werte. Allerdings exisitieren auch Spalten, die sehr viele NULL-Werte aufweisen. Beispielsweise Emissionen_g_pro_km.
Nachfolgend werden die NULL-Werte in einer heatmap visuaisiert.
sns.set_theme(style="ticks", color_codes=True)
# Identifizieren der NULL Werte via Heatmap
sns.heatmap(AutoDF.isnull(),
yticklabels=False,
cbar=False,
cmap='viridis');
In der Heatmap ist zu erkennen, dass sehr viele NULL-Werte in den Spalten Untertitel, Fahrzeughalter, Verbrauch_l_pro_100km und Emissionen_g_pro_km exisitieren.
Nachfolgend werden hierfür nochmal die exakten Mengen ausgegeben:
print(AutoDF.isnull().sum())
Titel 0
Version 279
Untertitel 4941
Preis 0
Leasing 0
km 0
Erstzulassung 0
PS 130
Zustand 0
Fahrzeughalter 5961
Getriebe 0
Kraftstoff 0
Verbrauch_l_pro_100km 4103
Emissionen_g_pro_km 7120
Marke 0
Alufelgen 0
Sitzheizung 0
Klimaanlage 0
Einparkhilfe 0
Navigationssystem 0
Stadt 1879
dtype: int64
Die Features Verbrauch_l_pro_100km, Emissionen_g_pro_km, km (Kilometerstand) und PS sollen in unserem Use Case genauer untersucht werden. Daher sollen im Folgenden alle Zeilen mit NULL Values entfernt werden.
Das Feature Fahrzeughalter soll kompett entfernt werden, da dieses auch häufig nicht gepflegt wurde und auch nicht unbedingt aussagekräftig ist über den Zustand & Wert des Autos.
AutoDF = AutoDF[AutoDF['Verbrauch_l_pro_100km'].notna()]
AutoDF = AutoDF[AutoDF['Emissionen_g_pro_km'].notna()]
AutoDF = AutoDF[AutoDF['km'].notna()]
AutoDF = AutoDF[AutoDF['PS'].notna()]
print(AutoDF.isnull().sum())
Titel 0
Version 27
Untertitel 946
Preis 0
Leasing 0
km 0
Erstzulassung 0
PS 0
Zustand 0
Fahrzeughalter 1418
Getriebe 0
Kraftstoff 0
Verbrauch_l_pro_100km 0
Emissionen_g_pro_km 0
Marke 0
Alufelgen 0
Sitzheizung 0
Klimaanlage 0
Einparkhilfe 0
Navigationssystem 0
Stadt 379
dtype: int64
Als nächstes sollen alle Leasing Fahrzeuge aus dem DF entfernt werden. Diese waren nur als Werbung zwischen den eigentlichen Gebrauchtwagen Angeboten enthalten und verfälschen mit bspw. Preis (pro Monat als Leasing) die Statistiken.
# Prüfung ob Leasing Fahrzeuge enthalten sind (Leasing == True)
AutoDF["Leasing"].unique()
array([False, True])
# DF wird neu erstellt nur mit Datensätzen die Leasing == False sind (~AutoDF.Leasing)
AutoDF = AutoDF[~AutoDF.Leasing]
# Prüfung ob alle Leasing Fahrzeuge entfernt sind
AutoDF["Leasing"].unique()
array([False])
Die Spalte Leasing wird nun nicht mehr gebraucht und kann entfernt werden. Das gleiche gilt für die Spalte Zustand, da alle Fahrzeuge gebraucht sind und die Spalte Standort, da die benötigte Information Stadt bereits daraus abgezogen wurde.
Wie oben erklärt, soll auch die Spalte Fahrzeughalter entfernt werden.
# Prüfung ob wirklich nur gebrauchte Fahrzeuge enthalten sind
AutoDF["Zustand"].unique()
array(['Gebraucht'], dtype=object)
# Entfernen der beschriebenen Spalten
AutoDF = AutoDF.drop(columns=['Zustand','Leasing','Fahrzeughalter','Standort'])
Anpassung der Datentypen¶
Zunächst wird geprüft, welche Datentypen aktuell vorliegen
AutoDF.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4570 entries, 7 to 12178
Data columns (total 18 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Titel 4570 non-null object
1 Version 4543 non-null object
2 Untertitel 3627 non-null object
3 Preis 4570 non-null object
4 km 4570 non-null object
5 Erstzulassung 4570 non-null object
6 PS 4570 non-null object
7 Getriebe 4570 non-null object
8 Kraftstoff 4570 non-null object
9 Verbrauch_l_pro_100km 4570 non-null object
10 Emissionen_g_pro_km 4570 non-null object
11 Marke 4570 non-null object
12 Alufelgen 4570 non-null bool
13 Sitzheizung 4570 non-null bool
14 Klimaanlage 4570 non-null bool
15 Einparkhilfe 4570 non-null bool
16 Navigationssystem 4570 non-null bool
17 Stadt 4201 non-null object
dtypes: bool(5), object(13)
memory usage: 522.2+ KB
Als nächstes werden die Datentypen angepasst, indem numerische Spalten einer Datentypkonvertierung unterzogen werden.
AutoDF['Preis'] = AutoDF['Preis'].astype('int')
AutoDF['km'] = AutoDF['km'].astype('int')
AutoDF['PS'] = AutoDF['PS'].astype('int')
AutoDF['Emissionen_g_pro_km'] = AutoDF['Emissionen_g_pro_km'].astype('int')
AutoDF['Erstzulassung'] = AutoDF['Erstzulassung'].astype('float')
AutoDF['Verbrauch_l_pro_100km'] = AutoDF['Verbrauch_l_pro_100km'].astype('float')
Die Spalten Getriebe, Kraftstoff Marke und Land weisen jeweils nur eine geringe Menge verschiedener Ausprägungen vor. Daher werden diese Spalten im Typ categorical abgespeichert. Alle übrigen Spalten verbleiben als object.
AutoDF['Getriebe'] = AutoDF['Getriebe'].astype('category')
AutoDF['Kraftstoff'] = AutoDF['Kraftstoff'].astype('category')
AutoDF['Marke'] = AutoDF['Marke'].astype('category')
Nun liegt das Dataframe in einer Form vor, in der die explorative Datenanalyse durchgeführt werden kann.
AutoDF.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 4570 entries, 7 to 12178
Data columns (total 18 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Titel 4570 non-null object
1 Version 4543 non-null object
2 Untertitel 3627 non-null object
3 Preis 4570 non-null int32
4 km 4570 non-null int32
5 Erstzulassung 4570 non-null float64
6 PS 4570 non-null int32
7 Getriebe 4570 non-null category
8 Kraftstoff 4570 non-null category
9 Verbrauch_l_pro_100km 4570 non-null float64
10 Emissionen_g_pro_km 4570 non-null int32
11 Marke 4570 non-null category
12 Alufelgen 4570 non-null bool
13 Sitzheizung 4570 non-null bool
14 Klimaanlage 4570 non-null bool
15 Einparkhilfe 4570 non-null bool
16 Navigationssystem 4570 non-null bool
17 Stadt 4201 non-null object
dtypes: bool(5), category(3), float64(2), int32(4), object(4)
memory usage: 360.1+ KB
Die bereinigten Daten werden nochmal in einer neuen Tabelle in postgre SQL gesichert.
if not engine.has_table("autoscout24cars-cleaned"):
AutoDF.to_sql(name='autoscout24cars-cleaned',index=True, index_label='index',con=engine)
else:
print("table already exists")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [70], in <cell line: 1>()
----> 1 if not engine.has_table("autoscout24cars-cleaned"):
2 AutoDF.to_sql(name='autoscout24cars-cleaned',index=True, index_label='index',con=engine)
3 else:
NameError: name 'engine' is not defined
Deskriptive Statistik¶
Vorbereitung & allgemeine Untersuchung des DF¶
Nachfolgend werden alle numerischen Features in einer Liste gespeichert.
num_features=AutoDF.select_dtypes(include=np.number).columns.to_list()
num_features
['Preis',
'km',
'Erstzulassung',
'PS',
'Verbrauch_l_pro_100km',
'Emissionen_g_pro_km']
Gleiches wird für alle nicht numerischen Features durchgeführt.
cat_features=AutoDF.select_dtypes(exclude=np.number).columns.to_list()
cat_features
['Titel',
'Version',
'Untertitel',
'Getriebe',
'Kraftstoff',
'Marke',
'Alufelgen',
'Sitzheizung',
'Klimaanlage',
'Einparkhilfe',
'Navigationssystem',
'Stadt']
Für einen ersten Überblick über die Datenverteilung numerischer Features bietet sich die describe() Methode an. Diese gibt für jede Spalte die Anzahl, Durchschnitt, Standardabweichung, Minimum, Maximum sowie die Quartile an.
AutoDF.describe().transpose()
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Preis | 4570.0 | 22212.728228 | 24413.752948 | 1.0 | 7450.00 | 15999.0 | 27990.0 | 349900.0 |
| km | 4570.0 | 112090.814004 | 78410.721967 | 7.0 | 52954.25 | 98500.0 | 157000.0 | 729439.0 |
| Erstzulassung | 4570.0 | 2010.482932 | 7.251224 | 1990.0 | 2005.00 | 2011.0 | 2017.0 | 2021.0 |
| PS | 4570.0 | 196.174398 | 106.986416 | 5.0 | 125.00 | 165.0 | 239.0 | 772.0 |
| Verbrauch_l_pro_100km | 4570.0 | 7.351116 | 2.919708 | 0.0 | 5.50 | 6.7 | 8.8 | 61.0 |
| Emissionen_g_pro_km | 4570.0 | 177.867396 | 65.947109 | 0.0 | 135.00 | 163.0 | 213.0 | 595.0 |
Hier fällt bereits auf, dass teils extreme Werte vorliegen, wie bspw. max Werte beim Kilometerstand von 729.439km oder Fahrzeuge mit einem Verbrauch von 61 Liter auf 100km. Diese Werte fallen als extrem auf, da sie sehr stark vom vierten Quartil (75%) abweichen.
Der Durchschnittspreis der von uns Untersuchten Fahrzeuge liegt bei ca. 22.000€ und der durchschittliche Kilometerstand bei ca 112.000km
Nachfolgend wird die Anzahl der unique values je Feature ausgegeben.
for col in AutoDF.columns:
values = AutoDF[col].unique()
print(col, "has", len(AutoDF[col].unique()), "unique values")
Titel has 785 unique values
Version has 4311 unique values
Untertitel has 3372 unique values
Preis has 1817 unique values
km has 3334 unique values
Erstzulassung has 32 unique values
PS has 277 unique values
Getriebe has 4 unique values
Kraftstoff has 7 unique values
Verbrauch_l_pro_100km has 158 unique values
Emissionen_g_pro_km has 276 unique values
Marke has 63 unique values
Alufelgen has 2 unique values
Sitzheizung has 2 unique values
Klimaanlage has 2 unique values
Einparkhilfe has 2 unique values
Navigationssystem has 2 unique values
Stadt has 1067 unique values
Alle Features haben mindestens zwei verschiedene Ausprägungen. Variablen mit nur einem “unique value” würden keinen Mehrwert liefern für unsere Untersuchung.
Außerdem können wir bspw. erkennen, dass 63 verschiedene Automarken vertreten sind und die Fahrzeuge aus 1067 verschiedenen Städten angeboten werden und aus 32 unterschiedlichen Jahren stammen.
Als nächstes wird die Anzahl der Fahrzeuge pro Kraftstoffart ausgegeben.
print(AutoDF['Kraftstoff'].value_counts())
Benzin 3141
Diesel 1267
Elektro/Benzin 81
Elektro 38
Autogas (LPG) 21
Elektro/Diesel 21
Ethanol 1
Name: Kraftstoff, dtype: int64
Die häufigste Kraftstoffart ist Benzin, gefolgt von Diesel.
Alle anderen Kraftstoffarten kommen in Relation zur Gesamtmenge an Fahrzeugen eher selten vor.
Ebenso interessant ist die Anzahl der Fahrzeuge pro Getriebeart.
print(AutoDF['Getriebe'].value_counts())
Schaltgetriebe 2346
Automatik 2200
Halbautomatik 17
- (Getriebe) 7
Name: Getriebe, dtype: int64
Automatik und Schaltgetriebe kommen ungefähr gleich oft vor. Halbautomatikfahrzeuge kommen dagegen eher selten vor.
Außerdem fällt hier auf, dass 7 Datensätze keinen Wert haben für Getriebe - diese Datensätze werden als nächstes entfernt.
# Dataframe wird erstellt nur mit vorhandenen Werten bei "Getriebe"
AutoDF=AutoDF[AutoDF['Getriebe'].str.contains('- \(Getriebe\)')==False]
print(AutoDF['Getriebe'].value_counts())
Schaltgetriebe 2346
Automatik 2200
Halbautomatik 17
- (Getriebe) 0
Name: Getriebe, dtype: int64
Nachfolgend wird der prozentuale Anteil jeder Automarke in Bezug auf die Gesamtmasse aller Fahrzeuge ausgegeben.
print(AutoDF['Marke'].value_counts(normalize=True))
Audi 0.146833
BMW 0.135437
Mercedes-Benz 0.133684
Volkswagen 0.129520
Opel 0.050405
Ford 0.047556
Porsche 0.032435
Volvo 0.028490
MINI 0.021696
Skoda 0.020820
Peugeot 0.018190
Toyota 0.017532
SEAT 0.015779
Renault 0.015560
Mazda 0.015560
Jaguar 0.013807
Hyundai 0.012053
Alfa 0.011834
Kia 0.011615
Nissan 0.010958
Fiat 0.010739
Citroen 0.008766
Land 0.007890
Honda 0.007890
Cupra 0.007670
smart 0.005260
Mitsubishi 0.005041
Dacia 0.004821
Saab 0.004602
Aston 0.004602
Suzuki 0.004383
Jeep 0.003945
Maserati 0.003726
Chevrolet 0.003287
Lexus 0.003287
Dodge 0.002192
Ferrari 0.002192
Subaru 0.001972
Bentley 0.001972
SsangYong 0.001534
Abarth 0.001534
Daihatsu 0.001315
Alpina 0.001315
Chrysler 0.001096
HUMMER 0.001096
MG 0.000877
Lancia 0.000877
Sonstige 0.000877
Cadillac 0.000657
Daewoo 0.000657
Tesla 0.000438
DS 0.000438
Maybach 0.000438
Rover 0.000438
Infiniti 0.000438
Lamborghini 0.000438
Rolls-Royce 0.000219
Corvette 0.000219
Lada 0.000219
Polestar 0.000219
Caterham 0.000219
Aixam 0.000219
Lincoln 0.000219
Name: Marke, dtype: float64
Die häufigste in unserem Abzug vorkommende Automarke ist Audi, dicht gefolgt von von BMW und Mercedes-Benz.
Sehr selten vorkommende Automarken sind bspw. Lincoln, Aixam und Caterham.
Um allgemein noch einen guten Überblick über die Verteilung der numerischen Variablen zu bekommen, werden Histogramme erzeugt.
# Erstellen von Histogrammen der numerischen Variablen
AutoDF.hist(bins=20, figsize=(20,15))
plt.show("notebook")
Für einzelne Variablen wie bspw. km oder PS lassen sich rechtsschiefe Verteilungen erkennen. Vor allem bei Erstzulassung lässt sich aber kein Schwerpunkt in der Vertilung erkennen, lediglich ein leichter Trend zu weniger alten Fahrzeugen.
Da vor allem der Preis für diese Untersuchung interessant ist, wird dieses Histogramm noch einmal detaillierter dargestellt.
#Erstellung eines detaillierten Histogramm zur Variable Preis
fig = px.histogram(AutoDF, x="Preis",title="Distribution over price (Euro)")
fig.show()
Korrelationsanalyse¶
Um eine erste Übersicht über mögliche Zusammenhänge zwischen den verschiedenen Variablen zu erhalten, wird zunächst ein Pairplot erstellt. Der Plot eignet sich besonders für numerische Variablen, durch farbliche Markierung kann allerdings auch eine kategoriale Variable dargestellt werden.
sns.pairplot(data=AutoDF, vars=["Preis","PS","km","Erstzulassung","Verbrauch_l_pro_100km","Emissionen_g_pro_km"],
hue="Kraftstoff",)
<seaborn.axisgrid.PairGrid at 0x19fb0266280>
Tatsächlich können im Pairplot Zusammenhänge zwischen einzelnen Variablen erkannt werden. Vor allem die starke Korrelation zwischen Verbrauch und Emissionen fällt im Plot auf, ist allerdings selbstverständlich da mit höherem Verbrauch in der Regel auch mehr Emissionen erzeugt werden. Doch auch weniger starke Abhängigkeiten können erkannt werden wie bspw. zwischen PS und Preis oder zwischen PS und Verbrauch.
Durch die farbliche Markierung der Kraftstoffart lässt sich hier auch schon gut erkennen, dass Benzin Fahrzeuge eher einen höheren Verbrauch und höhere Emissionen erzeugen als Diesel Fahrzeuge. Auch Autogas scheint tendentiell mehr Emissionen zu erzeugen als Diesel Fahrzeuge.
Nach der optischen Darstellung sollen nun im nächsten Schritt die Abhängigkeiten noch einmal in Zahlen dargestellt werden.
# Erstellen einer Korrelationsmatrix
corr_matrix = AutoDF.corr()
corr_matrix
| Preis | km | Erstzulassung | PS | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Preis | 1.000000 | -0.421786 | 0.375126 | 0.701054 | 0.234156 | 0.232313 | -0.147829 | 0.002652 | -0.089297 | 0.037044 | 0.041534 |
| km | -0.421786 | 1.000000 | -0.568111 | -0.127463 | 0.210769 | 0.255970 | 0.108523 | -0.119208 | -0.031420 | -0.153058 | -0.142417 |
| Erstzulassung | 0.375126 | -0.568111 | 1.000000 | 0.117229 | -0.496235 | -0.506678 | -0.055640 | 0.201850 | 0.068506 | 0.311526 | 0.315454 |
| PS | 0.701054 | -0.127463 | 0.117229 | 1.000000 | 0.563397 | 0.579788 | -0.141854 | 0.011839 | -0.142537 | 0.015200 | 0.062163 |
| Verbrauch_l_pro_100km | 0.234156 | 0.210769 | -0.496235 | 0.563397 | 1.000000 | 0.933004 | -0.046658 | -0.074132 | -0.080756 | -0.147325 | -0.118214 |
| Emissionen_g_pro_km | 0.232313 | 0.255970 | -0.506678 | 0.579788 | 0.933004 | 1.000000 | -0.043258 | -0.079571 | -0.082951 | -0.153974 | -0.123025 |
| Alufelgen | -0.147829 | 0.108523 | -0.055640 | -0.141854 | -0.046658 | -0.043258 | 1.000000 | 0.055907 | 0.179344 | 0.042522 | 0.047007 |
| Sitzheizung | 0.002652 | -0.119208 | 0.201850 | 0.011839 | -0.074132 | -0.079571 | 0.055907 | 1.000000 | 0.125800 | 0.203946 | 0.244613 |
| Klimaanlage | -0.089297 | -0.031420 | 0.068506 | -0.142537 | -0.080756 | -0.082951 | 0.179344 | 0.125800 | 1.000000 | 0.065015 | 0.099932 |
| Einparkhilfe | 0.037044 | -0.153058 | 0.311526 | 0.015200 | -0.147325 | -0.153974 | 0.042522 | 0.203946 | 0.065015 | 1.000000 | 0.320108 |
| Navigationssystem | 0.041534 | -0.142417 | 0.315454 | 0.062163 | -0.118214 | -0.123025 | 0.047007 | 0.244613 | 0.099932 | 0.320108 | 1.000000 |
# Erstellen einer Heatmap um Abhängigkeiten zwischen den verschiedenen Variablen zu visualisieren
# Einstellung um nur den relevanten Teil der Matrix zu plotten
mask = np.zeros_like(corr_matrix)
mask[np.triu_indices_from(mask)]= True
# Erstellen der Heatmap
plt.subplots(figsize=(11, 15))
heatmap = sns.heatmap(corr_matrix,
mask = mask,
square = True,
linewidths = .5,
cmap = 'coolwarm',
cbar_kws = {'shrink': .6,
'ticks' : [-1, -.5, 0, 0.5, 1]},
vmin = -1,
vmax = 1,
annot = True,
annot_kws = {"size": 10})
Durch die Korrelationsmatrix sowie deren Visualisierung mit einer Heatmap können Korrelationen zwischen den verschiedenen Variablen auf einen Blick erkannt werden. Die farblich besonders saturierten Feleder (dunkelblau und dunkelrot) weisen auf besonders starke Abhängigkeit hin.
Da die offensichtlichsten Korrelationen (bspw. zwischen PS, Verbrauch und Emissionen) naheliegend und daher nicht besonders interessant sind, soll im Folgenden näher untersucht werden, welche Faktoren einen besonderen Einfluss auf den Preis haben.
# Berechnung der Korrelationen der einzelnen Variablen zur Variable "Preis"
corr = AutoDF.corr()
corr['Preis'].sort_values(ascending=False)
Preis 1.000000
PS 0.701054
Erstzulassung 0.375126
Verbrauch_l_pro_100km 0.234156
Emissionen_g_pro_km 0.232313
Navigationssystem 0.041534
Einparkhilfe 0.037044
Sitzheizung 0.002652
Klimaanlage -0.089297
Alufelgen -0.147829
km -0.421786
Name: Preis, dtype: float64
Von den numerischen Variablen haben PS, km und Erstzulassung den höchsten Einfluss auf den Preis. Diese Variablen sollen daher näher untersucht werden. Dazu wird ein lmplot genutzt:
# Plot mit Trendlinie für PS & Preis
sns.lmplot(x='PS', y='Preis', data=AutoDF,
line_kws={'color': 'darkred'}, ci=False);
# Plot mit Trendlinie für km & Preis
sns.lmplot(x='km', y='Preis', data=AutoDF,
line_kws={'color': 'darkred'}, ci=False);
# Plot mit Trendlinie für Erstzulassung & Preis
sns.lmplot(x='Erstzulassung', y='Preis', data=AutoDF,
line_kws={'color': 'darkred'}, ci=False)
<seaborn.axisgrid.FacetGrid at 0x19fb91510d0>
Zusätzlich wird hier noch ein Boxplot erstellt, an welchem die Verteilung sowie Ausreißer besser erkannt werden können. Hier fällt auf, dass Ausreißer vor allem Luxusmarken wie Lamborghini, Bentley oder Porsche sind oder sehr teuere Modelle von bspw. BMW (BMW Z8).
# Erstellung eines Boxplots zur Preis & Erstzulassung
fig = px.box(data_frame=AutoDF,x="Erstzulassung", y="Preis",
hover_name="Titel")
fig.show()
Wie auch zuvor schon vermutet lässt sich hier nochmal klar bestätigen (durchschnittlich):
1. Mit steigenden PS steigt auch der Preis
2. Mit steigendem Kilometerstand sinkt der Preis
3. Mit steigendem Jahr der Erstzulassung steigt auch der Preis
Marke & Preis¶
Mit Hilfe eines Boxplots wollen wir außerdem untersuchen, wie sich die Preisverteilung bei den unterschiedlichen Automarken verhält. Um das besonders übersichtlich zu gestalten, wird die Anzeige aufsteigend nach dem Durchschnittspreis je Marke sortiert:
#sortieren der Marken nach Durchschnittspreis
sorted_nb = AutoDF.groupby(['Marke'])['Preis'].median().sort_values()
#sorted_nb
#Anpassen der seaborn Plotgröße um den Plot übersichtlich darzustellen
sns.set(rc={'figure.figsize':(15,15)})
#Erzeugen des Plots
sns.boxplot(x=AutoDF['Preis'], y=AutoDF['Marke'], order=list(sorted_nb.index),orient="h")
<AxesSubplot:xlabel='Preis', ylabel='Marke'>
Am Plot mit Sortierung lässt sich gut erkennen, dass Luxus-Automarken wie Lamborghini, Aston Martin und Rolls-Royce auch bei gebrauchten Fahrzeugen im Schnitt die teuersten Angebote darstellen. Vor allem bei Lamborghini und Aston Martin ist fällt auch, dass die Preisspanne innerhalb der vier Quartile des Boxplots sehr groß ist.
Günstige Fahrzeuge werden von den Marken Daewoo, Daihatsu und Rover angeboten. Am Beispiel Rover können wir erkennen, dass auf Grund einer geringen Auswahl an Fahrzeugangeboten mit einem sehr hohen Kilometerstand schnell ein sehr geringer durschnittlicher Preis entstehen kann:
AutoDF.loc[AutoDF['Marke']=='Rover']
| Titel | Version | Untertitel | Preis | km | Erstzulassung | PS | Getriebe | Kraftstoff | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Marke | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | Stadt | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3558 | Rover 75 | 2.0 V6 Club Leer Memory Clima . | NaN | 1650 | 303358 | 1999.0 | 150 | Schaltgetriebe | Benzin | 9.4 | 232 | Rover | False | False | False | False | False | APELDOORN |
| 3903 | Rover 75 | 2.5 V6 Sterling 177Pk Automaat (6 CILINDER, CL... | NaN | 4945 | 157651 | 2000.0 | 177 | Automatik | Benzin | 11.6 | 286 | Rover | False | False | False | False | False | IJssel |
Ausstattung & Preis¶
Als nächstes soll untersucht werden, inwiefern die Ausstattungsmerkmale einen eindeutigen Einfluss auf den Preis haben.
Austtattung=['Klimaanlage','Alufelgen','Sitzheizung','Einparkhilfe','Navigationssystem']
Austtattung
['Klimaanlage',
'Alufelgen',
'Sitzheizung',
'Einparkhilfe',
'Navigationssystem']
fig, ax = plt.subplots(2, 3, figsize=(15, 10))
for var, subplot in zip(Austtattung, ax.flatten()):
sns.boxplot(x=var, y='Preis', data=AutoDF, ax=subplot)
Fazit: durch die Boxplots lässt sich leider kaum eine Auswirkung der Ausstattungsmerkmale auf den Preis erkennen. Vermutlich ist die Beschreibung der Ausstattung oft nicht detailliert gepflegt. Man kann vermuten, dass vor allem bei modernen und teuren Autos eine Klimaanlage bspw. selbstverständlich ist und daher nicht extra im Untertitel der Anzeige erwähnt wird.
Kraftstoff & Preis¶
# Gruppieren des DF nach Kraftstoff mit durschnittlichem Preis
PriceAveragePerKraftstoff=AutoDF.groupby(by="Kraftstoff")["Preis"].mean()
# Erzeugen des Bar Plots mit den zuvor erzeugten Gruppierungen
PriceAveragePerKraftstoff.plot(kind="bar",figsize=(12,6),color="m",title="Durschnittlicher Preis nach Kraftstoff")
<AxesSubplot:title={'center':'Durschnittlicher Preis nach Kraftstoff'}, xlabel='Kraftstoff'>
Am Balkendiagramm können wir erkennen, dass Elektrofahrzeuge und Hybride im Durschnitt am teuersten gehandelt werden, Fahrzeuge mit Ethanol oder Autogas als Kraftstoff am günstigsten.
Da bei diesen Untersuchungen allerdings auch die Anzahl an vorliegenden Datensätzen eine Rolle spielt, wird diese noch einmal zusätzlich in einem weiteren Plot visualisiert:
#Anpassen der seaborn Plotgröße um den Plot übersichtlich darzustellen
sns.set(rc={'figure.figsize':(12,8)})
sns.stripplot(data=AutoDF, x="Kraftstoff", y="Preis" , size=3 )
<AxesSubplot:xlabel='Kraftstoff', ylabel='Preis'>
Hier können wir erkennen, dass nur für Benzin und Diesel sehr viele Datensätze vorliegen - vor allem Ethanol scheint nur durch einen Datensatz vertreten zu sein und sollte daher mit Vorsicht interpretiert werden.
fig=px.scatter(AutoDF,x="PS",y="Preis",color="Emissionen_g_pro_km",size="Verbrauch_l_pro_100km",
hover_data=["Marke","Titel","Kraftstoff"],title="Price over PS",
trendline="ols")
fig.show()
Getriebe & Preis¶
Als nächstes wird der Einfluss der Art des Getriebes auf den Preis untersucht:
# Erstellen eines erweiterten Boxplots zu Getriebe & Preis
sns.boxenplot(data=AutoDF, x="Getriebe", y="Preis");
Am Boxplot können wir erkennen, das Fahrzeuge mit Schaltgetriebe im Durchschnitt am günstigsten verkauft werden, Fahrzeuge mit Automatik im Durchschnitt am teuersten.
Das kann noch etwas detaillierter dargstellt werden:
#Erstellen einzelner DF nach Getriebe für folgende Visualisierung
Automatik=AutoDF[AutoDF["Getriebe"]=="Automatik"]
Schaltgetriebe=AutoDF[AutoDF["Getriebe"]=="Schaltgetriebe"]
Halbautomatik=AutoDF[AutoDF["Getriebe"]=="Halbautomatik"]
#Erstellen von Series Objekten mit den entsprechenden Preisen
npAutomatik = Automatik["Preis"]
npSchaltgetriebe = Schaltgetriebe["Preis"]
npHalbautomatik = Halbautomatik["Preis"]
# Zusammenfassen der Series Objekte zu einer Liste
data = [npAutomatik.values, npSchaltgetriebe.values, npHalbautomatik.values]
# Parameter für Plot
group_labels = ['Automatik', 'Schaltgetriebe', 'Halbautomatik']
colors = ['#462EDE', '#DE2EBE', '#FF8033']
# Erstellen des Plots mit zuvor erzeugter Liste und Parametern
fig = ff.create_distplot(data, group_labels,
bin_size=3000, show_rug=False)
# Anpassung Titetl
fig.update_layout(title_text='Preisverteilung nach Getriebe')
fig.show()
Untersuchung von Unterschieden zwischen Automarken¶
Neben den zuvor schon festgestellten Unterschieden im Preis sollen nun auch noch weitere Unterschiede zwischen den Automarken untersucht werden. Dazu werden die numerischen Variablen der Marken zunächst nach dem Durchschnitt gruppiert.
MarkenGruppiert=AutoDF.groupby(by="Marke").mean()
MarkenGruppiert
| Preis | km | Erstzulassung | PS | Verbrauch_l_pro_100km | Emissionen_g_pro_km | Alufelgen | Sitzheizung | Klimaanlage | Einparkhilfe | Navigationssystem | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Marke | |||||||||||
| Abarth | 18979.142857 | 34271.285714 | 2017.142857 | 162.571429 | 6.585714 | 155.714286 | 0.000000 | 0.000000 | 0.571429 | 0.142857 | 0.285714 |
| Aixam | 7950.000000 | 11149.000000 | 2010.000000 | 8.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Alfa | 16468.685185 | 108397.574074 | 2006.777778 | 184.629630 | 8.590741 | 205.333333 | 0.166667 | 0.018519 | 0.185185 | 0.074074 | 0.055556 |
| Alpina | 33811.333333 | 130511.000000 | 2010.500000 | 366.333333 | 8.533333 | 208.333333 | 0.000000 | 0.333333 | 0.000000 | 0.333333 | 0.333333 |
| Aston | 112095.238095 | 44050.190476 | 2008.952381 | 492.619048 | 15.819048 | 373.095238 | 0.000000 | 0.142857 | 0.142857 | 0.000000 | 0.047619 |
| Audi | 25795.776119 | 110393.247761 | 2012.222388 | 224.489552 | 6.992239 | 170.143284 | 0.126866 | 0.256716 | 0.292537 | 0.240299 | 0.313433 |
| BMW | 21189.422330 | 132068.305825 | 2007.970874 | 216.035599 | 7.697735 | 186.805825 | 0.156958 | 0.257282 | 0.176375 | 0.265372 | 0.322006 |
| Bentley | 73719.333333 | 93012.666667 | 2007.111111 | 536.444444 | 16.922222 | 395.333333 | 0.111111 | 0.111111 | 0.111111 | 0.222222 | 0.222222 |
| Cadillac | 13830.000000 | 140875.000000 | 2011.000000 | 264.000000 | 12.433333 | 289.333333 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Caterham | 27999.000000 | 22900.000000 | 2000.000000 | 135.000000 | 8.300000 | 164.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Chevrolet | 12699.133333 | 88319.800000 | 2011.133333 | 171.866667 | 7.793333 | 186.066667 | 0.066667 | 0.400000 | 0.133333 | 0.200000 | 0.200000 |
| Chrysler | 10049.800000 | 146629.600000 | 2004.800000 | 241.200000 | 10.100000 | 234.800000 | 0.400000 | 0.000000 | 0.200000 | 0.200000 | 0.000000 |
| Citroen | 7289.725000 | 140696.250000 | 2009.200000 | 119.725000 | 6.122500 | 151.075000 | 0.125000 | 0.100000 | 0.275000 | 0.175000 | 0.125000 |
| Corvette | 49500.000000 | 71000.000000 | 2014.000000 | 466.000000 | 12.300000 | 282.000000 | 0.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 |
| Cupra | 35797.257143 | 23084.542857 | 2020.257143 | 246.857143 | 6.094286 | 160.657143 | 0.057143 | 0.485714 | 0.285714 | 0.485714 | 0.628571 |
| DS | 17240.000000 | 52900.000000 | 2016.500000 | 155.500000 | 5.700000 | 133.000000 | 0.000000 | 1.000000 | 0.500000 | 0.000000 | 1.000000 |
| Dacia | 20206.818182 | 24118.045455 | 2019.090909 | 59.818182 | 1.618182 | 37.636364 | 0.000000 | 0.000000 | 0.045455 | 0.000000 | 0.000000 |
| Daewoo | 2354.666667 | 81918.666667 | 2001.000000 | 73.666667 | 7.166667 | 173.333333 | 0.000000 | 0.000000 | 0.333333 | 0.000000 | 0.000000 |
| Daihatsu | 3136.833333 | 128231.500000 | 2004.333333 | 72.000000 | 5.250000 | 124.333333 | 0.500000 | 0.000000 | 0.333333 | 0.166667 | 0.000000 |
| Dodge | 27937.900000 | 102139.900000 | 2008.900000 | 305.800000 | 12.680000 | 302.400000 | 0.200000 | 0.100000 | 0.100000 | 0.100000 | 0.200000 |
| Ferrari | 107657.000000 | 41797.400000 | 2005.400000 | 481.300000 | 17.550000 | 372.900000 | 0.100000 | 0.000000 | 0.100000 | 0.000000 | 0.000000 |
| Fiat | 7768.265306 | 113770.163265 | 2007.020408 | 106.551020 | 6.530612 | 153.408163 | 0.326531 | 0.061224 | 0.285714 | 0.122449 | 0.102041 |
| Ford | 16488.728111 | 86040.525346 | 2013.313364 | 143.092166 | 6.213825 | 151.198157 | 0.304147 | 0.170507 | 0.299539 | 0.308756 | 0.262673 |
| HUMMER | 30887.800000 | 141125.400000 | 2005.400000 | 337.000000 | 16.820000 | 396.800000 | 0.200000 | 0.200000 | 0.200000 | 0.200000 | 0.000000 |
| Honda | 13044.277778 | 108555.638889 | 2009.805556 | 162.583333 | 7.302778 | 171.750000 | 0.277778 | 0.138889 | 0.305556 | 0.277778 | 0.166667 |
| Hyundai | 13648.000000 | 91240.472727 | 2013.109091 | 158.690909 | 7.152727 | 170.127273 | 0.145455 | 0.290909 | 0.363636 | 0.181818 | 0.254545 |
| Infiniti | 19890.000000 | 132210.000000 | 2013.500000 | 265.500000 | 9.050000 | 210.500000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Jaguar | 32026.746032 | 104132.015873 | 2007.158730 | 329.238095 | 10.461905 | 252.000000 | 0.158730 | 0.158730 | 0.269841 | 0.174603 | 0.285714 |
| Jeep | 17115.277778 | 122080.388889 | 2008.388889 | 176.555556 | 9.961111 | 242.166667 | 0.166667 | 0.277778 | 0.222222 | 0.166667 | 0.333333 |
| Kia | 18223.358491 | 75401.566038 | 2015.433962 | 155.433962 | 6.369811 | 157.301887 | 0.169811 | 0.415094 | 0.264151 | 0.320755 | 0.377358 |
| Lada | 13445.000000 | 11500.000000 | 2018.000000 | 106.000000 | 6.200000 | 141.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Lamborghini | 262400.000000 | 38195.000000 | 2007.000000 | 570.500000 | 20.450000 | 460.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Lancia | 4420.000000 | 134231.000000 | 2005.750000 | 152.000000 | 9.450000 | 224.250000 | 0.000000 | 0.000000 | 0.000000 | 0.250000 | 0.000000 |
| Land | 30803.250000 | 155212.055556 | 2011.250000 | 255.972222 | 10.391667 | 260.805556 | 0.055556 | 0.222222 | 0.083333 | 0.305556 | 0.305556 |
| Lexus | 13204.400000 | 168577.866667 | 2005.666667 | 239.466667 | 9.720000 | 230.400000 | 0.000000 | 0.266667 | 0.133333 | 0.200000 | 0.266667 |
| Lincoln | 5950.000000 | 259841.000000 | 1999.000000 | 204.000000 | 11.900000 | 283.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| MG | 9210.000000 | 64014.250000 | 1999.500000 | 125.250000 | 7.550000 | 181.250000 | 0.500000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| MINI | 13069.808081 | 106059.323232 | 2010.444444 | 136.181818 | 6.120202 | 146.202020 | 0.212121 | 0.323232 | 0.343434 | 0.242424 | 0.242424 |
| Maserati | 56921.470588 | 87515.764706 | 2009.647059 | 397.529412 | 14.223529 | 337.000000 | 0.117647 | 0.352941 | 0.176471 | 0.176471 | 0.235294 |
| Maybach | 74994.500000 | 124500.000000 | 2009.500000 | 540.500000 | 13.800000 | 328.500000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Mazda | 12035.676056 | 109152.661972 | 2010.577465 | 135.619718 | 6.749296 | 164.760563 | 0.323944 | 0.239437 | 0.323944 | 0.169014 | 0.197183 |
| Mercedes-Benz | 29056.142623 | 112974.018033 | 2010.145902 | 244.031148 | 8.284590 | 199.239344 | 0.126230 | 0.288525 | 0.209836 | 0.296721 | 0.304918 |
| Mitsubishi | 8879.869565 | 127835.608696 | 2007.434783 | 134.608696 | 6.765217 | 168.913043 | 0.260870 | 0.130435 | 0.347826 | 0.130435 | 0.086957 |
| Nissan | 9995.260000 | 112635.000000 | 2009.660000 | 134.500000 | 6.922000 | 168.240000 | 0.140000 | 0.200000 | 0.340000 | 0.220000 | 0.260000 |
| Opel | 12099.721739 | 98926.069565 | 2011.569565 | 138.086957 | 6.315652 | 153.156522 | 0.234783 | 0.234783 | 0.408696 | 0.234783 | 0.247826 |
| Peugeot | 8839.566265 | 126257.445783 | 2008.602410 | 126.662651 | 6.415663 | 154.650602 | 0.180723 | 0.180723 | 0.289157 | 0.108434 | 0.132530 |
| Polestar | 69900.000000 | 8200.000000 | 2021.000000 | 476.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Porsche | 57766.459459 | 97910.763514 | 2006.675676 | 342.918919 | 10.845270 | 258.182432 | 0.108108 | 0.250000 | 0.277027 | 0.155405 | 0.216216 |
| Renault | 12700.661972 | 124671.661972 | 2006.619718 | 130.971831 | 7.236620 | 167.943662 | 0.295775 | 0.070423 | 0.309859 | 0.126761 | 0.239437 |
| Rolls-Royce | 119900.000000 | 104000.000000 | 2005.000000 | 460.000000 | 15.900000 | 385.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| Rover | 3297.500000 | 230504.500000 | 1999.500000 | 163.500000 | 10.500000 | 259.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| SEAT | 17321.236111 | 84424.777778 | 2014.902778 | 155.069444 | 5.673611 | 138.263889 | 0.250000 | 0.541667 | 0.180556 | 0.486111 | 0.486111 |
| Saab | 7827.428571 | 181520.333333 | 2002.904762 | 181.000000 | 9.114286 | 218.000000 | 0.333333 | 0.238095 | 0.380952 | 0.142857 | 0.142857 |
| Skoda | 18458.947368 | 89110.115789 | 2015.410526 | 142.378947 | 5.589474 | 136.473684 | 0.189474 | 0.494737 | 0.389474 | 0.357895 | 0.263158 |
| Sonstige | 17442.500000 | 137740.250000 | 2003.750000 | 101.000000 | 3.225000 | 85.500000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| SsangYong | 11278.571429 | 104561.000000 | 2013.285714 | 159.142857 | 6.514286 | 172.142857 | 0.000000 | 0.571429 | 0.285714 | 0.571429 | 0.142857 |
| Subaru | 12847.444444 | 165414.888889 | 2008.666667 | 170.888889 | 8.511111 | 203.666667 | 0.222222 | 0.222222 | 0.333333 | 0.000000 | 0.333333 |
| Suzuki | 5576.100000 | 137590.800000 | 2004.600000 | 99.800000 | 7.060000 | 158.800000 | 0.300000 | 0.100000 | 0.350000 | 0.100000 | 0.050000 |
| Tesla | 99563.000000 | 33300.000000 | 2015.000000 | 400.500000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.500000 | 0.000000 |
| Toyota | 12268.900000 | 121399.000000 | 2008.800000 | 132.400000 | 6.548750 | 155.075000 | 0.162500 | 0.137500 | 0.400000 | 0.125000 | 0.125000 |
| Volkswagen | 17188.986464 | 115568.905245 | 2011.702200 | 146.967851 | 6.291709 | 155.333333 | 0.219966 | 0.291032 | 0.384095 | 0.323181 | 0.380711 |
| Volvo | 19385.423077 | 154742.623077 | 2010.223077 | 205.007692 | 7.077692 | 173.261538 | 0.200000 | 0.315385 | 0.323077 | 0.169231 | 0.200000 |
| smart | 6064.958333 | 88368.583333 | 2004.750000 | 70.250000 | 4.862500 | 115.416667 | 0.458333 | 0.125000 | 0.375000 | 0.000000 | 0.000000 |
# Erstellen eines Barcharts zum durchschnittlichen Verbrauch pro Marke
fig=px.bar(x=MarkenGruppiert.index,y=MarkenGruppiert["Verbrauch_l_pro_100km"],title="Durchschnittlicher Verbrauch pro Automarke (Liter/100km)")
fig.show()
Hier fällt auf, dass Luxus- & Sportmarken wie bspw. Ferrari, Lamborghini und Bentley im Schnitt den höchsten Verbrauch haben. Reine Elektromarken wie Polestar oder Tesla haben logischerweise einen durchschnittlichen Verbrauch von 0.
Als nächstes soll die Eigenschaft PS untersucht werden auf Unterschiede zwischen den Automarken.
#sortieren der Marken nach Durchschnitts PS
sorted_ps = AutoDF.groupby(['Marke'])['PS'].median().sort_values()
#Anpassen der Größe des Plots
sns.set(rc={'figure.figsize':(15,15)})
#Erzeugen des Plots
sns.boxplot(x=AutoDF['PS'], y=AutoDF['Marke'], order=list(sorted_ps.index),orient="h")
<AxesSubplot:xlabel='PS', ylabel='Marke'>
Ähnlich wie beim Verbrauch fallen auch hier bei den PS Luxusmarken wie Lamborghini & Bentley auf. Interessant ist hier jedoch, das auch Maybach sehr weit vorne dabei ist, zuvor jedoch nicht beim Verbrauch in den Top 3 gelandet ist (lediglich Platz 9 wie in Liste unten zu sehen ist). Maybach scheint daher eher effiziente Motoren zu verwenden.
sorted_verbrauch = AutoDF.groupby(['Marke'])['Verbrauch_l_pro_100km'].median().sort_values()
sorted_verbrauch
Marke
Aixam 0.00
Dacia 0.00
Tesla 0.00
Polestar 0.00
Sonstige 2.40
smart 4.90
Daihatsu 4.90
SEAT 5.40
Skoda 5.40
Cupra 5.50
DS 5.70
Ford 6.00
Kia 6.10
MINI 6.10
Volkswagen 6.10
SsangYong 6.20
Opel 6.20
Lada 6.20
Citroen 6.20
Peugeot 6.40
Audi 6.40
Nissan 6.40
Fiat 6.40
Suzuki 6.40
Mitsubishi 6.60
Chevrolet 6.60
Toyota 6.65
Mazda 6.70
Volvo 6.75
Abarth 6.80
Renault 7.00
Daewoo 7.00
Hyundai 7.20
Honda 7.20
Mercedes-Benz 7.50
MG 7.50
BMW 7.55
Chrysler 7.80
Caterham 8.30
Subaru 8.60
Alpina 8.70
Alfa 8.75
Lancia 8.80
Infiniti 9.05
Jeep 9.10
Saab 9.40
Land 9.50
Lexus 9.80
Rover 10.50
Porsche 11.30
Dodge 11.60
Lincoln 11.90
Jaguar 11.90
Corvette 12.30
Maybach 13.80
Cadillac 14.70
Maserati 14.70
Rolls-Royce 15.90
Aston 16.40
Bentley 17.10
HUMMER 18.10
Ferrari 18.60
Lamborghini 20.45
Name: Verbrauch_l_pro_100km, dtype: float64
Kartenvisualisierung¶
Als nächstes werden wird der Standort der zum Verkauf angebotenen Fahrzeuge in einer Landkarte visualisiert.
Für diese Zwecke wurde beim Webcrawling das Attribut Location von Autoscout24 abgezogen und anschließend in der Datenaufbereitung der Stadtname und das Land als extra Spalte angelegt.
Mithilfe des Geolocators werden jeder Stadt Longitude und Latitude zugeordnet und im Dataframe geoDF gespeichert. Dieses Dataframe wird anschließend über den Index mit dem AutoDF gejoined.
Aufgrund der Datenmenge wird für die Kartenvisualisierung nur ein Ausschnitt von 100 Datenpunkte verwendet. Diese werden in AutoDFsmall gespeichert.
AutoDFsmall = AutoDF[0:100]
geolocator = Nominatim(user_agent="my_app")
geoDF = pd.DataFrame()
for city in AutoDFsmall.index:
try:
location = geolocator.geocode(AutoDFsmall['Stadt'][city])
geoDF = geoDF.append({"longitude": location.longitude, "latitude": location.latitude}, ignore_index=True)
except:
geoDF = geoDF.append({"longitude": None, "latitude": None}, ignore_index=True)
geoDF
| longitude | latitude | |
|---|---|---|
| 0 | 13.322287 | 52.457257 |
| 1 | 9.278869 | 45.639544 |
| 2 | 11.048029 | 46.314475 |
| 3 | 8.816553 | 50.520168 |
| 4 | 8.764870 | 51.718960 |
| 5 | 7.136807 | 51.594201 |
| 6 | 11.280749 | 50.893925 |
| 7 | 11.280749 | 50.893925 |
| 8 | 7.340479 | 51.320742 |
| 9 | 9.278869 | 45.639544 |
| 10 | 11.048029 | 46.314475 |
| 11 | 10.992412 | 45.438496 |
| 12 | 11.048029 | 46.314475 |
| 13 | 8.241656 | 50.082038 |
| 14 | 13.738144 | 51.049329 |
| 15 | 11.048029 | 46.314475 |
| 16 | 6.759562 | 51.434999 |
| 17 | 11.280749 | 50.893925 |
| 18 | 10.037038 | 45.220864 |
| 19 | 4.746916 | 45.710702 |
| 20 | 11.048029 | 46.314475 |
| 21 | 11.048029 | 46.314475 |
| 22 | 9.149364 | 49.974054 |
| 23 | 11.048029 | 46.314475 |
| 24 | 11.048029 | 46.314475 |
| 25 | 4.654599 | 50.462995 |
| 26 | 16.786484 | 48.069744 |
| 27 | 6.229550 | 50.770291 |
| 28 | -100.445882 | 39.783730 |
| 29 | 6.601410 | 51.545898 |
| 30 | 7.989620 | 50.959863 |
| 31 | 7.529418 | 49.774820 |
| 32 | 11.904747 | 48.732142 |
| 33 | 9.964009 | 53.886745 |
| 34 | 7.219664 | 51.481811 |
| 35 | 8.818337 | 53.434064 |
| 36 | 13.474937 | 54.353479 |
| 37 | 11.048029 | 46.314475 |
| 38 | 9.951305 | 52.152164 |
| 39 | 11.048029 | 46.314475 |
| 40 | 10.992412 | 45.438496 |
| 41 | 11.048029 | 46.314475 |
| 42 | 7.219985 | 51.538039 |
| 43 | 14.117785 | 51.041750 |
| 44 | 16.288722 | 47.107142 |
| 45 | 10.834281 | 47.768675 |
| 46 | 11.048029 | 46.314475 |
| 47 | 11.048029 | 46.314475 |
| 48 | 11.048029 | 46.314475 |
| 49 | 11.048029 | 46.314475 |
| 50 | 11.048029 | 46.314475 |
| 51 | 7.733330 | 50.466700 |
| 52 | 7.661086 | 47.714697 |
| 53 | 11.048029 | 46.314475 |
| 54 | 15.969177 | 47.280937 |
| 55 | 11.048029 | 46.314475 |
| 56 | 11.028736 | 50.977797 |
| 57 | 7.660722 | 47.612090 |
| 58 | 8.651177 | 49.872775 |
| 59 | 11.048029 | 46.314475 |
| 60 | 8.241656 | 50.082038 |
| 61 | 11.048029 | 46.314475 |
| 62 | 10.160149 | 48.304488 |
| 63 | 12.231224 | 51.846592 |
| 64 | 8.344097 | 49.998629 |
| 65 | 8.531007 | 52.019101 |
| 66 | 7.465279 | 51.514227 |
| 67 | 10.000654 | 53.550341 |
| 68 | 8.754158 | 45.839713 |
| 69 | 12.482932 | 41.893320 |
| 70 | 8.124701 | 52.302900 |
| 71 | 6.555575 | 50.541002 |
| 72 | 7.849400 | 47.996090 |
| 73 | 11.048029 | 46.314475 |
| 74 | 6.435364 | 51.194698 |
| 75 | 13.791598 | 48.108609 |
| 76 | 12.540308 | 51.347271 |
| 77 | 11.048029 | 46.314475 |
| 78 | 13.046481 | 47.798135 |
| 79 | 6.849350 | 51.297326 |
| 80 | 11.048029 | 46.314475 |
| 81 | 11.048029 | 46.314475 |
| 82 | 11.048029 | 46.314475 |
| 83 | 11.048029 | 46.314475 |
| 84 | 11.048029 | 46.314475 |
| 85 | 10.000654 | 53.550341 |
| 86 | 11.048029 | 46.314475 |
| 87 | 6.787122 | 50.661262 |
| 88 | 11.048029 | 46.314475 |
| 89 | 11.048029 | 46.314475 |
| 90 | 11.048029 | 46.314475 |
| 91 | 13.769831 | 47.933996 |
| 92 | 11.048029 | 46.314475 |
| 93 | 7.372762 | 47.598553 |
| 94 | 12.006399 | 49.058276 |
| 95 | 13.523585 | 52.484340 |
| 96 | 11.048029 | 46.314475 |
| 97 | 11.048029 | 46.314475 |
| 98 | 11.048029 | 46.314475 |
| 99 | 7.819339 | 49.141945 |
#Index von AutoDF zurücksetzen, da aufgrund der Entfernung der Null-Values bei Verbrauch und Emissionen viele Zeilen weggefallen sind
#sonst kann nicht mit GeoDF gejoined werden
AutoDFsmall = AutoDFsmall.reset_index(drop=True)
#Join von GeoDF und AutoDF über Index
AutoDFsmall = pd.merge(AutoDFsmall, geoDF, left_index=True, right_index=True)
Unter Verwendung von Longitude und Latitude werden die Fahrzeugstandorte auf einer Folium Map visualisiert.
Zusätzlich wird jedem Datenpunkt eine Pop-Up Beschreibung hingefügt, welche Stadtname, Autobeschreibung und Preis beinhaltet.
m = folium.Map([50.0 , 10.0],zoom_start=4)
for i in AutoDFsmall.index:
try:
folium.Marker( location=[ AutoDFsmall['latitude'][i], AutoDFsmall['longitude'][i] ], popup = [AutoDFsmall['Stadt'][i], AutoDFsmall['Titel'][i], AutoDFsmall['Preis'][i]]).add_to(m)
except:
continue
m
Regression¶
In diesem Kapitel wird ein einfaches Regressionsmodell zur Bestimmmung des Fahrzeugpreises auf Basis ausgewählter Features berechnet.
Hierfür wird die lineare Regression gewählt. Da die Regression nicht Fokus des Projekts ist, wurde auf einen Split der Daten in Trainings- und Testdaten verzichtet.
Zudem wird lediglich ein Modell berechnet und somit auf den Vergleich verschiedener Modell mit anschließender Auswahl des besten Modells verzichtet.
Für das Modell wurden jene Features ausgewählt, die in der vorherigen explorativen Datenanalyse die größte Korrelation zu Preis aufweisen.
Dazu gehören folgende Features:
PS
km
Erstzulassung
Kraftstoff
Verbrauch_l_pro_100km
Emissionen_g_pro_km
Da die Features Verbrauch und Emissionen eine sehr hohe Korrelation untereinander aufweisen, soll nur eines der beiden Features verwendet werden. Da die Abhängigkeit von Preis zu Verbrauch minimal höher ist als zu Emissionen, wird der Verbrauch gewählt.
# Fit Model
lm = smf.ols(formula='Preis ~ PS + km + Kraftstoff + Erstzulassung + Verbrauch_l_pro_100km', data=AutoDF).fit()
# Full summary
lm.summary()
| Dep. Variable: | Preis | R-squared: | 0.634 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.633 |
| Method: | Least Squares | F-statistic: | 787.4 |
| Date: | Tue, 13 Sep 2022 | Prob (F-statistic): | 0.00 |
| Time: | 19:56:18 | Log-Likelihood: | -50282. |
| No. Observations: | 4563 | AIC: | 1.006e+05 |
| Df Residuals: | 4552 | BIC: | 1.007e+05 |
| Df Model: | 10 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | -9.719e+05 | 9.9e+04 | -9.814 | 0.000 | -1.17e+06 | -7.78e+05 |
| Kraftstoff[T.Benzin] | -580.8589 | 3276.059 | -0.177 | 0.859 | -7003.525 | 5841.807 |
| Kraftstoff[T.Diesel] | 5084.3293 | 3309.632 | 1.536 | 0.125 | -1404.155 | 1.16e+04 |
| Kraftstoff[T.Elektro] | 2.346e+04 | 4266.256 | 5.500 | 0.000 | 1.51e+04 | 3.18e+04 |
| Kraftstoff[T.Elektro/Benzin] | 5039.1362 | 3770.621 | 1.336 | 0.181 | -2353.111 | 1.24e+04 |
| Kraftstoff[T.Elektro/Diesel] | 7925.3502 | 4632.848 | 1.711 | 0.087 | -1157.281 | 1.7e+04 |
| Kraftstoff[T.Ethanol] | -753.9051 | 1.51e+04 | -0.050 | 0.960 | -3.04e+04 | 2.89e+04 |
| PS | 141.3709 | 3.127 | 45.204 | 0.000 | 135.240 | 147.502 |
| km | -0.0869 | 0.004 | -23.866 | 0.000 | -0.094 | -0.080 |
| Erstzulassung | 482.5563 | 48.872 | 9.874 | 0.000 | 386.743 | 578.370 |
| Verbrauch_l_pro_100km | 631.4028 | 140.165 | 4.505 | 0.000 | 356.611 | 906.194 |
| Omnibus: | 4435.504 | Durbin-Watson: | 1.800 |
|---|---|---|---|
| Prob(Omnibus): | 0.000 | Jarque-Bera (JB): | 423808.392 |
| Skew: | 4.457 | Prob(JB): | 0.00 |
| Kurtosis: | 49.364 | Cond. No. | 6.18e+07 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 6.18e+07. This might indicate that there are
strong multicollinearity or other numerical problems.
Das Modell hat einen R-Squared von 63,1% und einen Adjusted R-Squared von 63,0% und schneidet somit mittelmäßig ab.
R-squared ist eine Kennzahl zur Beurteilung der Anpassungsgüte eines Modells und nimmt einen Wert zwischen 0% und 100% an. Als Bezugsbasis wird der Durchschnitt verwendet.
In statistischen Methoden wird meist lieber der adjusted R-squared genutzt. Da dieser die degrees of freedom miteinbezieht, lässt sich durch adj. R-squared einen besseren Rückschluss auf die Gesamtpopulation der Datensätze ziehen. Dieser ist meistens etwas schlechter als R-squared.
F-statistics ist die Menge der systematischen Varianz (MSM) geteilt durch die Menge der unsystematischen Varianz (MSR). Die Kennzahl gibt an, in welcher Höhe das Modell die Ergebnisausgabe der abhängigen Variable verbessert hat, verglichen zu Ungenauigkeit im Modell. Je höher F-statistics, desto besser. Mit einem Wert von 781 ist F-Statistics schneidet auch diese Kennzahl mittelmäßig ab.
Verbesserungspotenzial gibt es bei den Featuren:
Die p-Values einer Kraftstoff Kategorien liegen über 0,05% und haben daher statistisch gesehen keinen Einfluss auf den Preis. Ein sinnvoller Schritt wäre hier das Zusammenfassen einiger Kraftstoffarten. Ethanol als Kraftstoff kommt in diesem Datensatz nur einmal vor und sollte für das Modell entfernt werden. Elektro/Diesel und Elektro/Benzin könnten beispielsweise in der Kategorie Hypride zusammengefasst werden. Anschließend kann das Modell nochmal trainiert werden und weitere Verbesserungspotentiale identifiziert werden.
Dies ist jedoch nicht mehr Fokus des Projekts. Diese lineare Regression dient lediglich als Ausblick, was mit diesem Datensatz noch alles möglich gewesen wäre.